
// First design decision: 
//
// Socket class is simple and there really is
// no point in doing anything fancy with it, is there?  All methods
// are straight-forward and documented. We know what we are talking
// about.
//
// For development, just call through to POSIX versions. Later can 
// push decision of how xp will be implemented.
// 
// POSIX: Dealing with EINTR.
//  - subclass / strategy (later)
//
// The class is nothing more than OO version of the undrlying socket
// fd. Since you can copy the underlying fds, you can copy the Socket
// (no attempt to disallow copying).

class Socket {
  public:

    class Address;

    // Throws runtime_error if socket() fails.  Assumed that if you
    // are creating a socket, you want a socket.
    Socket( int domain, int type, int protocol );
    virtual ~Socket();

    int shutdown( int how );
    
    int bind( Address const &addr );
    int listen( int backlog );
    Socket accept( Address &from );
    
    //                      - non-standard - 

    // Completeness would dictate defining 'set_blocking()' and
    // 'set_blocking()'. These are unlikely to be used.
    int set_nonblock();
  private:
    typedef int socket_t;
    socket_t fd_;
    Socket( socket_t fd );
};

#include <sys/socket.h>
#include <sys/types.h>

class Socket::Address {
  protected:
    typedef sockaddr_storage sockaddr_storage_t;
    sockaddr_storage_t storage_;
    Address( sockaddr_storage_t const & storage)
        : storage_(storage) {}
    Address();
  public:
    virtual ~Address() {}
    static Address Factory( sockaddr_storage_t const &storage );
    sa_family_t domain() const { return storage_.ss_family; }
  private:
    struct sockaddr *sockaddr() const { return (struct sockaddr*)&storage_; }
    virtual socklen_t len() const;
    friend class Socket;
};

#include <stdint.h>
#include <netinet/in.h>

// Possibly unclear / too complicated with internal factory stuff.
// Probably suffice to store the length in the base class and provide
// the external construction (subclass ctors).  Alternativley a set of
// reasonable ctors on the base class would suffice.
class InetAddress : public Socket::Address {
    socklen_t len() const { return sizeof( struct sockaddr_in ); }
  public:
    InetAddress( uint32_t addr, uint16_t port );
  private:
    InetAddress( const Socket::Address::sockaddr_storage_t &storage) 
        : Socket::Address(storage) {}

    // Allow factory to make this.
    friend Socket::Address 
    Socket::Address::Factory( const Socket::Address::sockaddr_storage_t &storage );
};

